package androidx.sqlite.db;

import android.content.Context;
import android.database.sqlite.SQLiteException;
import android.os.Build;
import android.os.Build.VERSION;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.List;

public abstract interface SupportSQLiteOpenHelper extends Closeable {
	@Nullable
	public abstract String getDatabaseName();

	@RequiresApi(api = 16)
	public abstract void setWriteAheadLoggingEnabled(boolean paramBoolean);

	public abstract SupportSQLiteDatabase getWritableDatabase();

	public abstract SupportSQLiteDatabase getReadableDatabase();

	public abstract void close();

	public static abstract class Callback {
		private static final String TAG = "SupportSQLite";
		public final int version;

		public Callback(int version) {
			this.version = version;
		}

		public void onConfigure(@NonNull SupportSQLiteDatabase db) {
		}

		public abstract void onCreate(@NonNull SupportSQLiteDatabase paramSupportSQLiteDatabase);

		public abstract void onUpgrade(@NonNull SupportSQLiteDatabase paramSupportSQLiteDatabase, int paramInt1, int paramInt2);

		public void onDowngrade(@NonNull SupportSQLiteDatabase db, int oldVersion, int newVersion) {
			throw new SQLiteException("Can't downgrade database from version " + oldVersion + " to " + newVersion);
		}

		public void onOpen(@NonNull SupportSQLiteDatabase db) {
		}

		public void onCorruption(@NonNull SupportSQLiteDatabase db) {
			Log.e("SupportSQLite", "Corruption reported by sqlite on database: " + db.getPath());
			if (!db.isOpen()) {
				deleteDatabaseFile(db.getPath());
				return;
			}
			List<Pair<String, String>> attachedDbs = null;
			try {
				try {
					attachedDbs = db.getAttachedDbs();
				} catch (SQLiteException localSQLiteException) {
				}
				try {
					db.close();
				} catch (IOException localIOException) {
				}
			} finally {
				// Pair<String, String> p;
				if (attachedDbs != null) {
					for (Pair<String, String> p : attachedDbs) {
						deleteDatabaseFile((String) p.second);
					}
				} else {
					deleteDatabaseFile(db.getPath());
				}
			}
		}

		private void deleteDatabaseFile(String fileName) {
			if ((fileName.equalsIgnoreCase(":memory:")) || (fileName.trim().length() == 0)) {
				return;
			}
			Log.w("SupportSQLite", "deleting the database file: " + fileName);
			try {
				if (Build.VERSION.SDK_INT >= 16) {
					SupportSQLiteCompat.Api16Impl.deleteDatabase(new File(fileName));
				} else {
					try {
						boolean deleted = new File(fileName).delete();
						if (!deleted) {
							Log.e("SupportSQLite", "Could not delete the database file " + fileName);
						}
					} catch (Exception error) {
						Log.e("SupportSQLite", "error while deleting corrupted database file", error);
					}
				}
			} catch (Exception e) {
				Log.w("SupportSQLite", "delete failed: ", e);
			}
		}
	}

	public static class Configuration {
		@NonNull
		public final Context context;
		@Nullable
		public final String name;
		@NonNull
		public final SupportSQLiteOpenHelper.Callback callback;
		public final boolean useNoBackupDirectory;

		Configuration(@NonNull Context context, @Nullable String name, @NonNull SupportSQLiteOpenHelper.Callback callback) {
			this(context, name, callback, false);
		}

		Configuration(@NonNull Context context, @Nullable String name, @NonNull SupportSQLiteOpenHelper.Callback callback, boolean useNoBackupDirectory) {
			this.context = context;
			this.name = name;
			this.callback = callback;
			this.useNoBackupDirectory = useNoBackupDirectory;
		}

		@NonNull
		public static Builder builder(@NonNull Context context) {
			return new Builder(context);
		}

		public static class Builder {
			Context mContext;
			String mName;
			SupportSQLiteOpenHelper.Callback mCallback;
			boolean mUseNoBackupDirectory;

			@NonNull
			public SupportSQLiteOpenHelper.Configuration build() {
				if (this.mCallback == null) {
					throw new IllegalArgumentException("Must set a callback to create the configuration.");
				}
				if (this.mContext == null) {
					throw new IllegalArgumentException("Must set a non-null context to create the configuration.");
				}
				if ((this.mUseNoBackupDirectory) && (TextUtils.isEmpty(this.mName))) {
					throw new IllegalArgumentException("Must set a non-null database name to a configuration that uses the no backup directory.");
				}
				return new SupportSQLiteOpenHelper.Configuration(this.mContext, this.mName, this.mCallback, this.mUseNoBackupDirectory);
			}

			Builder(@NonNull Context context) {
				this.mContext = context;
			}

			@NonNull
			public Builder name(@Nullable String name) {
				this.mName = name;
				return this;
			}

			@NonNull
			public Builder callback(@NonNull SupportSQLiteOpenHelper.Callback callback) {
				this.mCallback = callback;
				return this;
			}

			@NonNull
			public Builder noBackupDirectory(boolean useNoBackupDirectory) {
				this.mUseNoBackupDirectory = useNoBackupDirectory;
				return this;
			}
		}
	}

	public static abstract interface Factory {
		@NonNull
		public abstract SupportSQLiteOpenHelper create(@NonNull SupportSQLiteOpenHelper.Configuration paramConfiguration);
	}
}